package com.deyuanyun.pic.settings.service.base.impl;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import com.deyuanyun.pic.common.util.ImageUtil;
import com.deyuanyun.pic.common.util.ObjectUtil;
import com.deyuanyun.pic.common.util.ajax.AjaxResponse;
import com.deyuanyun.pic.common.util.web.Asserts;
import com.deyuanyun.pic.common.util.web.DownLoadUtil;
import com.deyuanyun.pic.settings.controller.dto.MyFileVO;
import com.deyuanyun.pic.settings.controller.dto.UserSessionVO;
import com.deyuanyun.pic.settings.domain.base.Attachment;
import com.deyuanyun.pic.settings.domain.base.AttachmentExample;
import com.deyuanyun.pic.settings.domain.util.DomainInitUtil;
import com.deyuanyun.pic.settings.mapper.base.AttachmentMapper;
import com.deyuanyun.pic.settings.service.base.UploadService;
import com.deyuanyun.pic.settings.support.cache.SessionCacheSupport;


/**
 * @author chace.cai   xu
 * @description
 * 附件上传相关
 * @date 2016/4/15
 */
@Service
public class UploadServiceImpl implements UploadService {
    static Logger logger=Logger.getLogger(UploadServiceImpl.class);

    @Autowired
    private AttachmentMapper attachmentMapper;
    @Value("${upload_file_dir}")
    String fileUploadDir;
   // @Value("${upload_file_tmp_dir}")
    //String fileUploadTmpDir;//临时存放路径

    @Value("${upload_file_allow_suffix}")
    String allowSuffix;//允许上传的后缀名
    
    @Override
    /**
     * 存放文件
     * @param multipartFile
     * @param fileVO
     * @return
     */
    public String saveStorageFile(MultipartFile multipartFile, MyFileVO fileVO)throws Exception{

        String fileName = multipartFile.getOriginalFilename();
        String nameSuff = com.deyuanyun.pic.common.util.FileUtils.getNameSuff(fileName);
        Asserts.assertTrue(allowSuffix != null, "未配置允许上传的文件类型");
        Asserts.assertTrue(allowSuffix.indexOf(nameSuff) != -1, nameSuff + "文件类型不允许上传");
        
        String businessId = fileVO.getBusinessId();
        if(fileVO.isOnlyOne() && StringUtils.isNotBlank(businessId)){
            //如果附件是唯一附件，比如头像，就把之前的标记删除。
            AttachmentExample example=new AttachmentExample();
            example.createCriteria().andBusinessIdEqualTo(businessId).andCustomTypeEqualTo(fileVO.getType()).andDeletedEqualTo((short)0);
            List<Attachment> attachmentList = attachmentMapper.selectByExample(example);
            for (int i = 0; i < attachmentList.size(); i++) {
                Attachment attachment = attachmentList.get(i);
                attachment.setDeleted((short)1);
                DomainInitUtil.initUpdateDomain(attachment, "标记删除，因为上传了新的附件");
                attachmentMapper.updateByPrimaryKeySelective(attachment);
            }
        }
        //CORRCTRL       
        String md5= DigestUtils.md5DigestAsHex(multipartFile.getBytes());//todo md5值 首先通过MD5值查找有无重复记录，有的话就复制一条出来，然后返回id
        String path1=(StringUtils.isBlank(fileVO.getType())?"other":fileVO.getType().toLowerCase());
        String newFileName= com.deyuanyun.pic.common.util.FileUtils.generateFileNameBySuff("","");//随机产生一个不带或者的文件名
        String newFileName1= newFileName + nameSuff;//接上后缀
        //String newFileName2= newFileName+"_s"+nameSuff;

        AttachmentExample example=new AttachmentExample();
        example.createCriteria().andUniqueIdentifiesEqualTo(md5);
        List<Attachment> attachmentList = attachmentMapper.selectByExample(example);
        UserSessionVO sessionVO= SessionCacheSupport.getSessionVO();
        if (ObjectUtil.isNotNullEmpty(attachmentList)){
            Attachment attachment=attachmentList.get(0);
            //根据md5查找有无重复记录，有的时候判断一下服务器上面是否存在文件，如果存在文件直接复制，如果没有就保存新的图片
            File existFile = new File(fileUploadDir + "/" + attachment.getPath());
            if(!existFile.exists()) {
                
                //新保存服务器上面不存在的文件
                File file1=new File(fileUploadDir + "/" + path1 + "/"+ newFileName1);
                new File(fileUploadDir + "/" + path1).mkdirs();
                byte[] b = multipartFile.getBytes();
                if((".jpg".equalsIgnoreCase(nameSuff) || ".bmp".equalsIgnoreCase(nameSuff) || ".png".equalsIgnoreCase(nameSuff))
                        && b.length > 200 * 1024){
                    //File file2=new File(fileUploadDir + "/" + path1 + "/"+ newFileName1);
                    FileUtils.writeByteArrayToFile(file1,b);
                    newFileName1 = newFileName1 + ".jpg";//压缩后都是jpg，为了保留原本的文件可追溯，所以直接在后面加.jpg
                    String file2Path = fileUploadDir + "/" + path1 + "/"+ newFileName1;
                    //BufferedImage bufferedImage = ImageIO.read(file1);
                    
                    ImageUtil.compressedImage(b, file2Path, 200);
                }else{
                    FileUtils.writeByteArrayToFile(file1,b);
                }
                //当文件不存在的时候重新设置附件表相关的数据，不拷贝无效数据
                attachment.setUniqueIdentifies(md5);
                attachment.setFileType(com.deyuanyun.pic.common.util.FileUtils.getNameSuff(fileName));//todo 要写一个专门的方法来转换
                attachment.setPath(path1+"/"+newFileName1);
            }

            //attachment.setFileType(fileVO.getType());
            //attachment.setSource(fileVO.getType());
            attachment.setCustomType(fileVO.getType());
            attachment.setRealName(fileName);
            DomainInitUtil.initCreateDomain(attachment);
            attachment.setDeleted((short) 0);
            attachment.setUpdateRemark(null);
            attachment.setUpdateRemark(null);
            if (StringUtils.isNotBlank(fileVO.getBusinessId())){
                attachment.setBusinessId(fileVO.getBusinessId());
            }else {
                attachment.setBusinessId(null);
            }
            attachmentMapper.insertSelective(attachment);

            if ("path".equalsIgnoreCase(fileVO.getResponseString())){
                return attachment.getPath();
            }else if ("id".equalsIgnoreCase(fileVO.getResponseString())){
                return attachment.getId();
            }else {//CK：什么鬼返回，简直要疯了。
                return "["+attachment.getId()+"]{"+attachment.getPath()+"}(" + fileName + ")";
            }

        }

        File file1=new File(fileUploadDir + "/" + path1 + "/"+ newFileName1);
        new File(fileUploadDir + "/" + path1).mkdirs();
        byte[] b = multipartFile.getBytes();
        if((".jpg".equalsIgnoreCase(nameSuff) || ".bmp".equalsIgnoreCase(nameSuff) || ".png".equalsIgnoreCase(nameSuff))
                && b.length > 200 * 1024){
            //File file2=new File(fileUploadDir + "/" + path1 + "/"+ newFileName1);
            FileUtils.writeByteArrayToFile(file1,b);
            newFileName1 = newFileName1 + ".jpg";//压缩后都是jpg
            String file2Path = fileUploadDir + "/" + path1 + "/"+ newFileName1;
            ImageUtil.compressedImage(b, file2Path, 200);
        }else{
            FileUtils.writeByteArrayToFile(file1,b);
        }

        Attachment attachment=new Attachment();
        attachment.setUniqueIdentifies(md5);
        DomainInitUtil.initCreateDomain(attachment);
        attachment.setUpdateDate(null);
        attachment.setUpdateUser(null);
        attachment.setDeleted((short)0);
        if (StringUtils.isNotBlank(fileVO.getBusinessId())){
            attachment.setBusinessId(fileVO.getBusinessId());
        }
        attachment.setPath(path1+"/"+newFileName1);
        attachment.setRealName(fileName);
        attachment.setCustomType(fileVO.getType());
        attachment.setFileType(com.deyuanyun.pic.common.util.FileUtils.getNameSuff(fileName));//todo 要写一个专门的方法来转换
        attachmentMapper.insertSelective(attachment);

        if ("path".equalsIgnoreCase(fileVO.getResponseString())){
            return path1+"/"+newFileName1;
        }else if ("id".equalsIgnoreCase(fileVO.getResponseString())){
            return attachment.getId();
        }else {//CK：什么鬼返回，简直要疯了。
            return "["+attachment.getId()+"]{"+path1+"/"+newFileName1+"}(" + fileName + ")";
        }

    }



    @Override
    /**根据附件id来更新附件表里面的业务id*/
    public void updateServiceIdByAttId(String id,String businessId){
        Attachment aa=attachmentMapper.selectByPrimaryKey(id);
        Asserts.assertTrue(aa!=null,"没有找到对应的附件记录"+id+">>"+businessId);
        Asserts.assertTrue(ObjectUtil.isEmptyAll(aa.getBusinessId()),"该附件已经属于其他业务"+id+">>>"+businessId);
        Attachment attachment=new Attachment();
        attachment.setId(id);
        UserSessionVO sessionVO= SessionCacheSupport.getSessionVO();
        attachment.setUpdateUser(sessionVO.getId());
        attachment.setUpdateDate(new Date());
        attachment.setBusinessId(businessId);
        attachmentMapper.updateByPrimaryKeySelective(attachment);
    }

    @Override
    /**根据附件id来清空附件关联*/
    public void deleteAttach(String id){
        Attachment aa=attachmentMapper.selectByPrimaryKey(id);
        Asserts.assertTrue(aa!=null,"没有找到对应的附件记录"+id+">>");
       // aa.setId(id);
        UserSessionVO sessionVO=SessionCacheSupport.getSessionVO();
        aa.setDeleted((short)1);
        aa.setBusinessId(null);
        aa.setUpdateRemark("该附件已经删除");
        aa.setUpdateUser(sessionVO.getId());
        aa.setUpdateDate(new Date());
        attachmentMapper.updateByPrimaryKey(aa);
    }


    @Override
    /**
     * 打包下载
     * @param businessId
     * @throws Exception
     */
    public void zipBusinessFiles(String businessId,String downFileName,String userAgent, HttpServletResponse response) throws UnsupportedEncodingException{
       // HttpServletResponse response= RequestResponseContext.getResponse();
        AttachmentExample example=new AttachmentExample();
        example.createCriteria().andBusinessIdEqualTo(businessId).andDeletedEqualTo((short)0);
        List<Attachment> attachmentList = attachmentMapper.selectByExample(example);
        //ServiceMapper sm = SpringAppliction.getBean(ServiceMapper.class);
        //com.deyuanyun.pm.domain.Service s = sm.selectByPrimaryKey(businessId);
        
        
        if (ObjectUtil.isEmptyAll(attachmentList)){
            response.setContentType("text/html;charset=UTF-8");
            response.setHeader("Content-Disposition","");
            AjaxResponse.sendText(response,"<script>top.alert('没有需要下载的附件!');</script>");
            return;
        }
        response.setContentType("APPLICATION/OCTET-STREAM");
        //统一命名规则
        String realName;// SessionCacheSupport.getSessionVO().getUsername();//getUserDetailInfo().getRealName();
        if(StringUtils.isNotBlank(downFileName)){
            realName = downFileName;
        }else{
            realName = SessionCacheSupport.getSessionVO().getUsername();//getUserDetailInfo().getRealName();
        }
        
        String fileName = DownLoadUtil.downLoadName(realName, userAgent);

        response.setHeader("Content-Disposition","attachment; filename="+ fileName +".zip");
        ZipOutputStream zos=null;
        try {
            zos = new ZipOutputStream(response.getOutputStream());
            for (Attachment attachment : attachmentList){
                zos.putNextEntry(new ZipEntry(attachment.getRealName()));
                FileInputStream fis = null;
                try{
                    fis = new FileInputStream(new File(fileUploadDir+"/"+attachment.getPath()));
                    byte[] buffer= IOUtils.toByteArray(fis);
                    zos.write(buffer, 0, buffer.length);
                    fis.close();
                } finally{
                    try {
                        fis.close();
                    } catch (Exception e) {
                    }
                }


            }
            zos.flush();

        }catch (Exception e){
            logger.error(">",e);
        }finally {
            try {
                zos.close();
            } catch (IOException e) {}
        }


    }

    @Override
    /**
     * 打包下载
     * @param businessId
     * @throws Exception
     */
    public void businessFiles(String businessId,String fileType,String downFileName,String userAgent, HttpServletResponse response) throws UnsupportedEncodingException{
       // HttpServletResponse response= RequestResponseContext.getResponse();
        AttachmentExample example=new AttachmentExample();
        example.createCriteria().andBusinessIdEqualTo(businessId).andCustomTypeEqualTo(fileType).andDeletedEqualTo((short)0);
        List<Attachment> attachmentList = attachmentMapper.selectByExample(example);
        //ServiceMapper sm = SpringAppliction.getBean(ServiceMapper.class);
        //com.deyuanyun.pm.domain.Service s = sm.selectByPrimaryKey(businessId);
        
        Asserts.assertTrue(!ObjectUtil.isEmptyAll(attachmentList), "没有需要下载的附件!");
        /*
        if (ObjectUtil.isEmptyAll(attachmentList)){
            response.setContentType("text/html;charset=UTF-8");
            response.setHeader("Content-Disposition","");
            //AjaxResponse.sendText(response,"<script>top.alert('没有需要下载的附件!');</script>");
            return;
        }*/
        response.setContentType("APPLICATION/OCTET-STREAM");
        //统一命名规则
        String realName;// SessionCacheSupport.getSessionVO().getUsername();//getUserDetailInfo().getRealName();
        if(StringUtils.isNotBlank(downFileName)){
            realName = downFileName;
        }else{
            realName = SessionCacheSupport.getSessionVO().getUsername();//getUserDetailInfo().getRealName();
        }
        
        String fileName = DownLoadUtil.downLoadName(realName, userAgent);
        if(attachmentList.size() == 1){
            Attachment attachment = attachmentList.get(0);
            //realName = attachment.getRealName();
            //fileName = DownLoadUtil.downLoadName(realName, userAgent);
            String nameSuff = com.deyuanyun.pic.common.util.FileUtils.getNameSuff(attachment.getPath());
            response.setHeader("Content-Disposition","attachment; filename="+ fileName + nameSuff);
            OutputStream os = null;
            try {
                os = response.getOutputStream();
                FileInputStream fis = null;
                try {
                    fis = new FileInputStream(new File(fileUploadDir+"/"+attachment.getPath()));
                    byte[] buffer= IOUtils.toByteArray(fis);
                    os.write(buffer, 0, buffer.length);
                    fis.close();
                } finally{
                    try {
                        fis.close();
                    } catch (Exception e) {
                        // TODO: handle exception
                    }
                }
                
            } catch (Exception e) {
                
            }finally{
                try {
                    os.close();
                } catch (Exception e2) {
                    // TODO: handle exception
                }
            }
            
        }else{
            response.setHeader("Content-Disposition","attachment; filename="+ fileName +".zip");
            ZipOutputStream zos=null;
            try {
                zos = new ZipOutputStream(response.getOutputStream());
                for (Attachment attachment : attachmentList){
                    zos.putNextEntry(new ZipEntry(attachment.getRealName()));
                    FileInputStream fis = null;
                    try {
                        fis = new FileInputStream(new File(fileUploadDir+"/"+attachment.getPath()));
                        byte[] buffer= IOUtils.toByteArray(fis);
                        zos.write(buffer, 0, buffer.length);
                        fis.close();
                    } finally{
                        try {
                            fis.close();
                        } catch (Exception e) {
                        }
                    }
                }
                zos.flush();

            }catch (Exception e){
                logger.error(">",e);
            }finally {
                try {
                    zos.close();
                } catch (IOException e) {}
            }

        }

    }



}
